Skip to content

[实例] 图片随鼠标微动

1.组件代码

vue
<template>
  <div
    class="container"
    ref="container"
    @mousemove="handleMouseMove"
    @mouseleave="handleMouseLeave"
  >
    <div class="imgage" ref="image" :style="imagePosition">
      <img src="https://picsum.photos/id/237/200/300" alt="" />
    </div>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        containerSize: null, // 外层容器尺寸
        innerSize: null, // 内层容器尺寸
        mouseX: 0, // 鼠标x坐标
        mouseY: 0, // 鼠标y坐标
      };
    },
    computed: {
      // 得到图片坐标
      imagePosition() {
        if (!this.innerSize || !this.containerSize) return;
        const extraWidth = this.innerSize.width - this.containerSize.width; // 多出狂赌
        const extraHeight = this.innerSize.height - this.containerSize.height;
        const left = (-extraWidth / this.containerSize.width) * this.mouseX;
        const top = (-extraHeight / this.containerSize.height) * this.mouseY;
        // return {
        //   left: left + "px",
        //   top: top + "px",
        // };
        return `translate(${left}px, ${top}px)`;
      },
      // 鼠标居中位置
      center() {
        return {
          x: this.containerSize.width / 2,
          y: this.containerSize.height / 2,
        };
      },
    },
    mounted() {
      this.setSize();
      this.mouseX = this.center.x;
      this.mouseY = this.center.y;
      window.addEventListener("resize", this.setSize);
    },
    destroyed() {
      window.removeEventListener("resize", this.setSize);
    },
    methods: {
      /**
       *  设置容器大小
       */
      setSize() {
        this.containerSize = {
          width: this.$refs.container.clientWidth,
          height: this.$refs.container.clientHeight,
        };
        this.innerSize = {
          width: this.$refs.image.clientWidth,
          height: this.$refs.image.clientHeight,
        };
      },
      /**
       * 鼠标移动事件
       */
      handleMouseMove(e) {
        const rect = this.$refs.container.getBoundingClientRect();
        this.mouseX = e.clientX - rect.left;
        this.mouseY = e.clientY - rect.top;
      },
      /**
       * 鼠标移出事件
       */
      handleMouseLeave() {
        this.mouseX = this.center.x;
        this.mouseY = this.center.y;
      },
    },
  };
</script>
<style>
  .container {
    width: 100%;
    height: 100%;
    position: relative;
  }
  .imgage {
    width: 110%;
    height: 110%;
    position: absolute;
    left: 0;
    top: 0;
  }
</style>

2.html 代码

html
<!-- /assets/demo/图片随鼠标微动.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片随鼠标微动</title>
    <!-- 引入 Vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
    <script src="../lib/vue@2.7.16.js"></script>
    <style>
      .container {
        width: 800px;
        height: 600px;
        position: relative;
        margin: 10vh auto;
        border: 1px solid #00f;
      }
      .imgage {
        width: 1200px;
        height: 900px;
        position: absolute;
        left: 0;
        top: 0;
        transition: 0.3s;
        border: 1px solid #faa;
        z-index: -10;
      }
      .imgage img {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
    <!-- Vue 实例化脚本 -->
    <script>
      new Vue({
        el: "#app",
        template: `
        <div
            class="container"
            ref="container"
            @mousemove="handleMouseMove"
            @mouseleave="handleMouseLeave"
        >
            <div class="imgage" ref="image" :style="imagePosition">
            <img src="https://picsum.photos/id/237/1200/900" alt="" />
            </div>
        </div>`,
        data: {
          containerSize: null, // 外层容器尺寸
          innerSize: null, // 内层容器尺寸
          mouseX: 0, // 鼠标x坐标
          mouseY: 0, // 鼠标y坐标
        },
        computed: {
          // 得到图片坐标
          imagePosition() {
            if (!this.innerSize || !this.containerSize) return;
            const extraWidth = this.innerSize.width - this.containerSize.width; // 多出狂赌
            const extraHeight =
              this.innerSize.height - this.containerSize.height;
            const left = (-extraWidth / this.containerSize.width) * this.mouseX;
            const top =
              (-extraHeight / this.containerSize.height) * this.mouseY;
            // return {
            //   left: left + "px",
            //   top: top + "px",
            // };
            return { transform: `translate(${left}px, ${top}px)` };
          },
          // 鼠标居中位置
          center() {
            console.log("center");
            return {
              x: this.containerSize.width / 2,
              y: this.containerSize.height / 2,
            };
          },
        },
        mounted() {
          console.log("mounted");
          this.setSize();
          this.mouseX = this.center.x;
          this.mouseY = this.center.y;
          window.addEventListener("resize", this.setSize);
        },
        destroyed() {
          window.removeEventListener("resize", this.setSize);
        },
        methods: {
          /**
           *  设置容器大小
           */
          setSize() {
            this.containerSize = {
              width: this.$refs.container.clientWidth,
              height: this.$refs.container.clientHeight,
            };
            this.innerSize = {
              width: this.$refs.image.clientWidth,
              height: this.$refs.image.clientHeight,
            };
          },
          /**
           * 鼠标移动事件
           */
          handleMouseMove(e) {
            console.log("handleMouseMove");
            const rect = this.$refs.container.getBoundingClientRect();
            this.mouseX = e.clientX - rect.left;
            this.mouseY = e.clientY - rect.top;
          },
          /**
           * 鼠标移出事件
           */
          handleMouseLeave() {
            this.mouseX = this.center.x;
            this.mouseY = this.center.y;
          },
        },
      });
    </script>
  </body>
</html>

Released under the MIT License.